package org.ee.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.ee.core.ProtocolRegistry;
import org.ee.handler.ChannelInit;
import org.ee.protocol.ProtocolA;
import org.ee.protocol.ProtocolB;
import org.springframework.stereotype.Component;

/**
 * netty启动器
 */
@Component
public class NettyServer {
    private static final Logger logger = LogManager.getLogger(NettyServer.class);

    private final ChannelInit channelInit;

    public NettyServer(ChannelInit channelInit) {
        this.channelInit = channelInit;
    }

    public void start(int port) {
        ProtocolRegistry.register(new ProtocolA());
        ProtocolRegistry.register(new ProtocolB());
        // 使用更合理的线程池配置：1个 bossGroup 线程，适配多核 CPU 的 workerGroup
        // 获取 CPU 核心数
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        // 单线程负责接受客户端连接
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // worker线程数可以根据机器核心数调整
        EventLoopGroup workerGroup = new NioEventLoopGroup(availableProcessors*2);
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            //全局设置缓冲区
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024) // 设置等待队列大小
                    /*
                     全局设置缓冲区,跟linux操作系统有关，
                        可以使用sysctl net.core.rmem_max查看操作系统的配置
                           sysctl net.core.rmem_default 默认的接收
                           cat /proc/sys/net/core/rmem_max
                            cat /proc/sys/net/core/wmem_max
                        虽然设置了1024*1024,但是操作系统为212992(默认)那么通过option获取的值为操作系统的
                        如果比操作系统小，则为设置的值
                     *但是如果设为小于1152的值，这是最小的值,则设为1152
                     *是因为操作系统的内存对齐和内核配置的原因。操作系统 可能会对缓冲区进行内存对齐或根据内核参数进行调整
                     *操作系统（尤其是 Linux 和 Windows）对网络缓冲区的大小通常会进行 对齐，通常会向上舍入到一个特定的边界。例如，操作系统可能会将缓冲区大小对齐为 512 字节或 1024 字节的倍数，这样可以提高内存管理的效率。
                           Linux 系统中，TCP 缓冲区的大小可能会被限制在某个固定的大小或对齐到一个特定的内存边界。
                            Windows 也有类似的对齐和系统配置，可能会调整设置的值。
                        因此，即使你在 Netty 中设置了 1024 字节作为接收缓冲区的大小，操作系统可能会根据其内部机制将其调整为 1152 字节。
                     */
                    .childOption(ChannelOption.SO_RCVBUF,1024*1024)// 设置接收缓冲区大小
                    .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024) // 设置发送缓冲区大小
                    .childOption(ChannelOption.SO_KEEPALIVE, true) // 开启TCP连接保持活动状态
                    .childOption(ChannelOption.TCP_NODELAY, true) // 关闭 Nagle 算法，提高实时性
                    .childOption(ChannelOption.SO_LINGER, 0) // 关闭 TCP 连接时不等待数据
                    .childHandler(channelInit);

            ChannelFuture future = bootstrap.bind(port).sync();
            logger.info("Netty server started on port {}", port);
            //等待服务器关闭
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException("Netty server startup interrupted", e);
        } finally {
            // 优雅地关闭线程池
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
